# -*- coding: UTF-8 -*-
'''
@Project ：push_rk
@File ：mytorchdemo.py
@IDE ：PyCharm
@Author ：苦瓜
@Date ：2025/10/13 8:37
@Note: Something beautiful is about to happen !
'''
import matplotlib.pyplot as plt
from sklearn.datasets import load_diabetes
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import MinMaxScaler
import torch
from torch import nn

# 糖尿病预测模型——基于GRU神经网络的时间序列分析
# 一、项目背景
# 糖尿病是一种全球性的慢性疾病，影响着数以亿计的人口。随着生活方式的改变和人口老龄化，糖尿病的发病率逐年上升。有效地预测和管理糖尿病对于提高患者的生活质量、减轻医疗系统的负担具有重要意义。时间序列分析在医疗健康领域有着广泛的应用，通过对患者历史数据的分析，可以预测疾病的发展趋势，为医生提供及时的干预建议。
# 二、项目目标
# 1.	数据处理：对糖尿病数据集进行预处理，包括数据归一化、构建时间序列样本等。
# 2.	模型构建：设计一个基于GRU神经网络的深度学习模型，用于学习时间序列数据中的复杂模式，并进行血糖水平预测。
# 3.	模型训练与优化：使用适当的损失函数和优化算法对模型进行训练，并通过迭代优化提高预测准确性。
# 4.	性能评估：在测试集上评估模型的预测性能，通过可视化预测结果与实际血糖水平的对比，验证模型的有效性。
# 5.	应用展望：探讨该模型在实际医疗场景中的应用潜力，如辅助医生制定个性化的治疗计划，提高糖尿病管理的效率和质量。
# 三、功能需求
# 1.	数据预处理：
data, target = load_diabetes(return_X_y=True)
# 使用MinMaxScaler对数据进行归一化处理。
data = MinMaxScaler().fit_transform(data)
target = MinMaxScaler().fit_transform(target.reshape(-1, 1))
# 构造序列数据：使用窗口大小为c的滑动窗口方法来构造输入特征x和对应的标签y。
c = 7
x = []
y = []
for i in range(len(data) - c):
    x.append(data[i:i+c])
    y.append(target[i+c])

# 修改数据类型
X = torch.tensor(x, dtype=torch.float32)
Y = torch.tensor(y, dtype=torch.float32)

# 切分数据
X_train, X_test, y_train, y_test = train_test_split(X, Y, shuffle=False, random_state=42)
print(f"""
    切分后数据的维度：
    X_train shape : {X_train.shape}
    X_test shape : {X_test.shape}
    y_train shape : {y_train.shape}
    y_test shape : {y_test.shape}
""")

# 2.	模型构建：
# 构建一个GRU模型
class MyGRU(nn.Module):

    def __init__(self, *args, **kwargs) -> None:
        super().__init__(*args, **kwargs)
        self.gru1 = nn.GRU(input_size=X_train.shape[2], hidden_size=10, batch_first=True)
        self.gru2 = nn.GRU(input_size=10, hidden_size=5, batch_first=True)
        self.fc = nn.Linear(in_features=5, out_features=1)

    def forward(self, inputs):
        x_, _ = self.gru1(inputs)
        x_, _ = self.gru2(x_)
        x_ = self.fc(x_[:, -1, :])
        return x_

if __name__ == '__main__':
    # 实例模型
    model = MyGRU()
    # 3.	模型训练：
    # 使用均方误差（MSE）作为损失函数。
    cost = nn.MSELoss()
    # 使用Adam优化器。
    optimizer = torch.optim.Adam(model.parameters(), lr=0.005)
    # 损失列表
    losses_ = []
    model.train()
    for epoch in range(1000):
        optimizer.zero_grad()
        y_pred_train = model(X_train)
        loss_ = cost(y_pred_train, y_train)
        losses_.append(loss_.item())
        loss_.backward()
        optimizer.step()
        if epoch % 10 == 0 :
            print(f"<Model train epoch : {epoch} , loss : {loss_}>")
    # 4.	模型预测与评估：
    # 使用训练好的模型对测试集进行预测。
    model.eval()
    with torch.no_grad():
        y_pred_test = model(X_test)
    # 将预测结果与实际标签进行可视化对比。
    plt.plot(y_pred_test, label="y pred test", c="r")
    plt.plot(y_test, label="y test", c="g")
    plt.legend()
    plt.show()
    # 损失图
    plt.plot(losses_, label='loss')
    plt.title("loss ")
    plt.show()
    # 5.	可视化：
    # 使用matplotlib库绘制预测结果与实际标签的对比图，其中预测结果用红色表示，实际标签用绿色表示。
    # 模型调优，考题中要求使用体现不同优化方案的要求，比如超参数方面的，比如说分类精度低的数据集的增强；比如说调整网络结构，比如说调整优化器学习率等；不能只是增加epoch大小，或者调整batch_size就可以，必须采用两种或者两种以上的调优方法进行调优，最终结论要给出综合各种方法调优得出的综合结论
    """
    模型调优：
        优化器：
            Adam ： <Model train epoch : 990 , loss : 0.03165184706449509>
            Adagrad : <Model train epoch : 990 , loss : 0.057760607451200485>
            RMSprop : <Model train epoch : 990 , loss : 0.045109059661626816>
            
        在优化器为Adam上，调整学习率
            学习率为 0.001：<Model train epoch : 990 , loss : 0.055411197245121>
            学习率为 0.005：<Model train epoch : 990 , loss : 0.0119865071028471>
            学习率为 0.0025: <Model train epoch : 990 , loss : 0.02681983821094036>
        在优化器为Adam，学习率为0.005时，模型为当前最优。
    """